from flask import render_template, session, request,jsonify
from flask import Blueprint
import json
from .. import app, mqtt
from ..models import *

import re
import binascii
import threading
from datetime import datetime
import time

from .help import Help
help = Help()

# session['username'] = '17740171896'
# session['password'] = '123456'

SERVER_ID = 'S001'


NODE_ONLINE       = "A1"
NODE_OFFLINE      = "A2"
NODE_OPEN_TAP     = "A3"
NODE_CLOSE_TAP    = "A4"
NODE_OPEN_TAP_OK  = "A5"
NODE_CLOSE_TAP_OK = "A6"

SITE_ONLINE = "B1"
SITE_OFFLINE = "B2"

idx = Blueprint('idx', __name__, template_folder='templates')


@idx.route('/')
def index():
    node = db.session.query(Node).all()
    print(node)
    return render_template('base.html')

@idx.route('/serial')
def serial_index():
    return render_template('serial.html')

@idx.route('/devices', methods=["GET","POST"])
def get_devices():
    telephone = request.args.get("telephone")
    sites = db.session.query(Site).filter(Site.user_id==User.id).filter(User.telephone==telephone).all()
    nodes = db.session.query(Node).filter(Node.user_id==User.id).filter(User.telephone==telephone).all()
    devices = {
        "nodes": [{ "cid": node.cid,
                    "name": node.name,
                    "version": node.version,
                    "position": node.position,
                    "alive": node.alive,
                    "status": node.status,
                    "tap_status": node.tap_status
                    } for node in nodes],
        "sites": [{ "cid": site.cid,
                    "name": site.name,
                    "version": site.version,
                    "alive": site.alive,
                    "status": site.status
                    } for site in sites]
        }
    # node_dict = {}
    # for node in nodes:
        # node_dict[node.cid] = {
                    # "name": node.name,
                    # "version": node.version,
                    # "position": node.position,
                    # "alive": node.alive,
                    # "status": node.status,
                    # "tap_status": node.tap_status
                # }
    # site_dict = {}
    # for site in sites:
        # site_dict[site.cid] = {
                    # "name": site.name,
                    # "version": site.version,
                    # "alive": site.alive,
                    # "status": site.status
                # }
    # devices = {
            # "nodes": node_dict,
            # "sites": site_dict
        # }
    return jsonify(devices)

"""
Mqtt 功能
包含：
    1、mqtt订阅用户的消息
    2、mqtt接收用户的消息并通过串口转发到响应的节点设备中
    3、mqtt
"""

# mqtt.subscribe(topic="$SYS/#", qos=0)
# mqtt.subscribe(topic="$SYS/brokers", qos=0)
mqtt.subscribe(topic="$SYS/brokers/emqx@127.0.0.1/clients/#", qos=0)
# 订阅用户与服务器之间的信息
mqtt.subscribe(topic="server/%s/#"%SERVER_ID, qos=0)
# 订阅终端设备的信息
# mqtt.subscribe(topic="dev/#", qos=0)

publish_site = "53010000"


REG_TELEPHONE_CONNECTED = re.compile(r'^\$SYS/brokers/(.*?)/clients/(\d{11})/(disconnected|connected)')
REG_DEVICE_CONNECTED = re.compile(r'^\$SYS/brokers/(.*?)/clients/([a-zA-Z0-9]{8})/(disconnected|connected)')

# REG_SERVER_GET_DEVICES = re.compile(r'^server/1/user/(\d{11})/get/deceives')

# REG_SERVER_GET_DEVICES = re.compile(r'^server/1/user/(\d{11})/get/deceives')
reg = {
    "get" : re.compile(r'^server/%s/dev/([a-z0-9]{8})/get/(.*)'%SERVER_ID),
    "post" : re.compile(r'^server/%s/dev/([a-z0-9]{8})/post/(.*)'%SERVER_ID),
}


def log_style(msg):
    print('\r\n')
    print('\t\t'+'*'*50)
    print('\t\t\t\ttime: ',datetime.today())
    print('\t\t\t\tprint: ',msg)
    print('\t\t'+'-'*50)
    print('\r\n')
def dev_online():
    pass


# 通过站点cid获取管理的节点信息
def site_get_nodes(cid=''):
    if cid:
        with app.app_context():
            nodes = db.session.query(Node).filter(Node.site_id==Site.id).filter(Site.cid==cid).all()
            info = [{
                    "cid": node.cid,
                    "name": node.name,
                    "lora_addr": node.lora_addr,
                    "version": node.version,
                    "position": node.position,
                    "alive": node.alive,
                    "alive_time": 0,
                    "status": node.status,
                    "tap_status": node.tap_status
                    } for node in nodes]
            return info


# mqtt接收消息函数
@mqtt.on_message()
def handle_mqtt_message(client, userdata, message):
    topic=message.topic
    payload=str(message.payload.decode())
    if REG_TELEPHONE_CONNECTED.match(topic):
        res = REG_TELEPHONE_CONNECTED.match(topic)
        with app.app_context():
            user = db.session.query(User).filter(User.telephone==res.group(2)).first()
            if user:
                if res.group(3) == "connected":
                    user.alive = True
                    log_style("user %s online!"%user.telephone)
                if res.group(3) == "disconnected":
                    user.alive = False
                    log_style("user %s offline!"%user.telephone)
                db.session.commit()
    if REG_DEVICE_CONNECTED.match(topic):
        res = REG_DEVICE_CONNECTED.match(topic)
        client_id = res.group(2)
        status = res.group(3)
        with app.app_context():
            site = db.session.query(Site).filter(Site.cid==client_id).first()
            if site:
                nodes = db.session.query(Node).filter(Node.site_id==Site.id).all()
                alive_devices= {}
                if status == "connected":
                    # 站点上线,获取所有节点状态
                    site.alive = True
                    alive_devices[site.cid] = True
                    for node in nodes:
                        alive_devices[node.cid] = node.alive
                    log_style("site %s online!"%site.cid)
                if status == "disconnected":
                    # 站点下线，所有节点一起下线
                    site.alive = False
                    alive_devices[site.cid] = False
                    for node in nodes:
                        node.alive = False
                        alive_devices[node.cid] = False
                    log_style("site %s offline!"%site.cid)
                db.session.commit()
                # 用户在线的话发送所有设备状态给用户
                user = db.session.query(User).filter(User.id==Site.user_id).first()
                if user:
                    if user.alive and alive_devices:
                        mqtt.publish(topic='user/%s/alives'%user.telephone,payload=json.dumps(alive_devices), qos=1)

    if reg['get'].match(topic):
        res = reg['get'].match(topic)
        cid = res.group(1)
        url = res.group(2)
        if url == "nodes":
            print("终端设备：%s 获取设备节点信息"%cid)
            info = site_get_nodes(cid)
            if info:
                print("返回节点信息给终端设备")
                mqtt.publish(topic='dev/%s/nodes'%cid,payload=json.dumps(info), qos=1)

# mqtt 日志打印函数
@mqtt.on_log()
def handle_logging(client, userdata, level, buf):
    print(level, buf)

"""
节点心跳包处理

思路：
        客户端连接上服务端后，在服务端会维护一个在线客户端列表。
    客户端每隔一段时间，向服务端发送一个心跳包，服务端受收到包以后，会更新客户端最近一次在线时间。
    一旦服务端超过规定时间没有接收到客户端发来的包，则视为掉线。

    1、打开一个线程，扫描在线的节点设备。
    2、根据节点设备的心跳包更新的最近在线时间和当前时间做差值
    3、超过规定时间，修改设备在线状态

"""
def heartHandler():
    while True:
        time.sleep(1)
        with app.app_context():
            nodes = db.session.query(Node).filter(Node.alive==True).all()
            for node in nodes:
                invertal_time = datetime.now() - node.alive_time
                if invertal_time.seconds > 3:
                    print("%s 设备超时下线 "%node.name)
                    node.alive = False
                    site = db.session.query(Site).filter(Site.id==node.site_id).first()
                    if site:
                        mqtt.publish(topic=site.cid,
                                     payload='{cid}/{type}/{cmd}'.format(cid=node.cid, type=TYPE, cmd=NODE_ALIVE_OFF)
                                    )
                else:
                    node.alive = True
            db.session.commit()


